#include "gd32l23x.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesUID.h"
#include "DevicesADC.h"


static uint16_t st_usADCDmaDatas[ADC0_SAMPLING_NUMBER][ADC0_SAMPLING_CHANNEL] = {0};


static void vADCDMAInit(void)
{
    /* ADC_DMA_channel configuration */
    dma_parameter_struct dma_data_parameter = {0};

    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* initialize DMA single data mode */
    dma_deinit(DMA_CH6);
    dma_data_parameter.periph_addr  = (uint32_t)&ADC_RDATA;
    dma_data_parameter.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_data_parameter.memory_addr  = (uint32_t)st_usADCDmaDatas;
    dma_data_parameter.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_data_parameter.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_data_parameter.number       = ADC0_SAMPLING_NUMBER * ADC0_SAMPLING_CHANNEL;
    dma_data_parameter.priority     = DMA_PRIORITY_HIGH;
    dma_data_parameter.request      = DMA_REQUEST_ADC;
    dma_init(DMA_CH6, &dma_data_parameter);

    dma_circulation_enable(DMA_CH6);

    /* enable DMA channel */
    dma_channel_enable(DMA_CH6);

    /* ADC DMA function enable */
    adc_dma_mode_enable();
}

void vADCInit(void)
{
    /* enable GPIOA clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);

    /* config the GPIO as analog mode */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
//    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_6);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_7);

    adc_deinit();

    /* config ADC clock */
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);

    /* ADC continuous function enable */
    adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC scan function enable */
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC_ROUTINE_CHANNEL, ADC0_SAMPLING_CHANNEL);

    /* ADC regular channel config */
    adc_routine_channel_config(0, ADC_SAMPLE_DCDC_OUT_VOLTAGE,          ADC0_SAMPLE_TIME);
    adc_routine_channel_config(1, ADC_SAMPLE_DCDC_OUT_CURRENT,          ADC0_SAMPLE_TIME);
    adc_routine_channel_config(2, ADC_SAMPLE_DCDC_INDUCTIVE_CURRENT,    ADC0_SAMPLE_TIME);
    adc_routine_channel_config(3, ADC_SAMPLE_DCDC_B_INDUCTIVE_CURRENT,  ADC0_SAMPLE_TIME);
    adc_routine_channel_config(4, ADC_SAMPLE_DCDC_IN_VOLTAGE,           ADC0_SAMPLE_TIME);
    adc_routine_channel_config(5, ADC_SAMPLE_DCDC_TEMPERATURE,          ADC0_SAMPLE_TIME);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC_ROUTINE_CHANNEL, ADC_EXTTRIG_ROUTINE_NONE);

    adc_external_trigger_config(ADC_ROUTINE_CHANNEL, ENABLE);

    /* enable ADC interface */
    adc_enable();
    vDelayMs(1);
    /* ADC calibration and reset calibration */
    adc_calibration_enable();

    vADCDMAInit();

    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC_ROUTINE_CHANNEL);
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
int32_t iADCGetDMAValue(uint8_t ucChannel)
{
    return ((float)st_usADCDmaDatas[0][ucChannel] * 3300) / 4095;
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetDMAValue(uint8_t ucChannel)
{
#if (ADC0_SAMPLING_NUMBER < 3)
    if(ucChannel >= ADC0_SAMPLING_CHANNEL)
        return 0.0f;

    return ((float)st_usADCDmaDatas[0][ucChannel]) * (3.3f / 4095.0f);

#else
    uint32_t uiValueSum = 0;
    uint16_t *pDatasHand = (uint16_t *)st_usADCDmaDatas;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF, i = 0;

    if(ucChannel >= ADC0_SAMPLING_CHANNEL)
        return 0.0f;

    pDatasHand += ucChannel;

    for(i = 0; i < ADC0_SAMPLING_NUMBER; ++i)
    {
        usValueNow  = *pDatasHand;
        uiValueSum += usValueNow;

        pDatasHand += ADC0_SAMPLING_CHANNEL;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    uiValueSum -= usValueMax + usValueMin;

    return ((float)uiValueSum / (ADC0_SAMPLING_NUMBER - 2) * (3.3f / 4095.0f));

#endif
}

/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetChannelValue(uint32_t adc_periph, uint8_t channel, uint32_t uiCnt)
{
    uint32_t uiValueSum = 0, i = 0;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF;

    /* ADC regular channel config */
    adc_routine_channel_config(0, channel, ADC0_SAMPLE_TIME);

    /* 切换通道后，丢弃第一次转换的数据 */
    /* wait the end of conversion flag */
    while(!adc_flag_get(ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    adc_flag_clear(ADC_FLAG_EOC);
    /* get regular channel sample value */
    adc_routine_data_read();

    for(i = 0; i < uiCnt; ++i)
    {
        /* wait the end of conversion flag */
        while(!adc_flag_get(ADC_FLAG_EOC));
        /* clear the end of conversion flag */
        adc_flag_clear(ADC_FLAG_EOC);
        /* get regular channel sample value */
        usValueNow = adc_routine_data_read();

        uiValueSum += usValueNow;;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

    return ((float)uiValueSum / (uiCnt - 2) * (3.3f / 4095.0f));
}
